// Copyright 2012 Google Inc. All Rights Reserved.

package com.google.appengine.syncserver.shared;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.JsonMappingException;

import java.io.IOException;
import java.util.logging.Logger;

/**
 * Client sends updates to server using this class.
 */
public class WriteUpdatesPageRequest {

  private static final String CHANGES = "changes";
  private static final String MAX_VERSION = "maxVersion";
  private static final String LAST_PAGE = "lastPage";
  private static final String FIRST_PAGE = "firstPage";
  private static final String PREFERENCE_NAME = "preferenceName";
  private static final String CLIENT_ID = "clientId";
  private static final String USERNAME = "username";
  private static final String GCM_REGISTRATION_ID = "gcmRegistrationId";


  // TODO(chintanraoh): Remove logging from here as Android and App Engine
  // logging are different.
  private static final Logger log = Logger.getLogger(WriteUpdatesPageRequest.class.getName());

  /**
   * Converts serialized JSON string to {@link WriteUpdatesPageRequest} object.
   *
   * @param str
   * @return {@link WriteUpdatesPageRequest} as read from the json string.
   */
  public static WriteUpdatesPageRequest valueOf(String str)
      throws JsonParseException, JsonMappingException, IOException {
    return (WriteUpdatesPageRequest) JsonUtils.stringToObject(str, WriteUpdatesPageRequest.class);
  }

  // Android shared preferences name.
  private final String preferencesName;

  // ClientId of the request.
  private final long clientId;

  // Whether this page is the first among the set of updates to be sent from
  // client.
  private final boolean firstPage;

  // Whether this page is the last among the set of updates to be sent from
  // client.
  private final boolean lastPage;

  // The username of the client.
  private final String username;

  // Max version number of server updates seen by the client.
  // Used to check whether the server is the same state when client
  // read updates from it and based on which client sent this update.
  private final long maxVersion;

  // Changes on the client which needs to uploaded to the server.
  // Changes are sharded and sent in the form of pages. This is one of the
  // sharded change list.
  private final PropertyChange[] changes;
  private final String gcmRegistrationId;

  /**
   * Used by client to create request object
   *
   * @param username Client's user name;.
   * @param clientId Client's client id.
   * @param preferencesName Preferences name.
   * @param firstPage Whether this page is the first page the client is sending.
   * @param lastPage Whether this page is the last page client is sending.
   * @param maxVersion
   * @param changes Changes to be sent to the server.
   */
  @JsonCreator
  public WriteUpdatesPageRequest(
      @JsonProperty(USERNAME) String username,
      @JsonProperty(CLIENT_ID) long clientId,
      @JsonProperty(PREFERENCE_NAME) String preferencesName,
      @JsonProperty(FIRST_PAGE) boolean firstPage,
      @JsonProperty(LAST_PAGE) boolean lastPage,
      @JsonProperty(MAX_VERSION) long maxVersion,
      @JsonProperty(GCM_REGISTRATION_ID) String gcmRegistrationId,
      @JsonProperty(CHANGES) PropertyChange[] changes) {
    this.preferencesName = preferencesName;
    this.clientId = clientId;
    this.firstPage = firstPage;
    this.username = username;
    this.maxVersion = maxVersion;
    this.lastPage = lastPage;
    this.changes = changes;
    this.gcmRegistrationId = gcmRegistrationId;
  }

  /**
   * @return the clientId
   */
  @JsonProperty(CLIENT_ID)
  public long getClientId() {
    return clientId;
  }

  /**
   * @return the gcm registractionId
   */
  @JsonProperty(GCM_REGISTRATION_ID)
  public String getGCMRegistrationId() {
    return gcmRegistrationId;
  }

  /**
   * @return the maxVersion
   */
  @JsonProperty(MAX_VERSION)
  public long getMaxVersion() {
    return maxVersion;
  }

  /**
   * @return the preferencesName
   */
  @JsonProperty(PREFERENCE_NAME)
  public String getPreferencesName() {
    return preferencesName;
  }

  @JsonProperty(CHANGES)
  public PropertyChange[] getPropertyChanges() {
    return changes;
  }

  /**
   * @return the user-name
   */
  @JsonProperty(USERNAME)
  public String getUsername() {
    return username;
  }

  /**
   * @return true if this first page among the set of pages to be sent
   * otherwise false.
   */
  @JsonProperty(FIRST_PAGE)
  public boolean isFirstPage() {
    return firstPage;
  }

  /**
   * @return true if this last page among the set of pages to be sent
   * otherwise false.
   */
  @JsonProperty(LAST_PAGE)
  public boolean isLastPage() {
    return lastPage;
  }

  @Override
  public String toString() {
    try {
      return JsonUtils.objectToString(this);
    } catch (JsonGenerationException e) {
      log.severe(e.getMessage());
    } catch (JsonMappingException e) {
      log.severe(e.getMessage());
    } catch (IOException e) {
      log.severe(e.getMessage());
    }
    return null;
  }
}
